package com.huizu.project.config;


import com.alibaba.fastjson2.JSON;
import com.huizu.common.core.domain.entity.SysUser;
import com.huizu.common.core.redis.RedisCache;
import com.huizu.common.exception.ServiceException;
import com.huizu.common.utils.SecurityUtils;
import com.huizu.common.utils.StringUtils;
import com.huizu.common.utils.ip.IpUtils;
import com.huizu.project.domain.ProUser;
import com.huizu.project.domain.ProUserTer;
import com.huizu.project.mapper.ProUserMapper;
import com.huizu.project.mapper.ProUserTerMapper;
import com.huizu.project.utils.TokenUtils;
import com.huizu.system.mapper.SysUserMapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
public class UserTokenLog {


    @Autowired
    private ProUserMapper proUserMapper;

    @Autowired
    private ProUserTerMapper proUserTerMapper;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private SysUserMapper sysUserMapper;



    //设置切点
//    @Pointcut("execution(* com.example.MyClass.*(..)) && !execution(* com.example.MyClass.excludeMethod(..))")
    @Pointcut("execution(* com.huizu.project.apiController.*.*(..))")
    public void webLogInfo() {
    }

    //设置切点
//    @Pointcut("execution(* com.example.MyClass.*(..)) && !execution(* com.example.MyClass.excludeMethod(..))")
    @Pointcut("@annotation(com.huizu.project.config.UserAspect)")
    public void userInfo() {
    }

    @Pointcut("@annotation(com.huizu.project.config.TerAspect)")
    public void terInfo() {
    }


    //定义切点，拦截所有标注了@PreventDuplicateSubmit注解的方法

    @Pointcut("execution(* com.huizu.project.apiController.*.*(..))")
    public void preventDuplicateSubmitPointcut() {
    }

    /**
     * 对前端所有接口进行切面  来获取日志
     * @param joinPoint
     * @throws Throwable
     */
    @Before("userInfo()")
    public void doBefore(JoinPoint joinPoint) throws Throwable
    {
        ServletRequestAttributes sra=(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request= Objects.requireNonNull(sra).getRequest();
        HttpServletResponse response = Objects.requireNonNull(sra).getResponse();
        String token = request.getHeader(TokenUtils.getAppTokenHeader());
        // 从请求头中获取 Token

//        if (request.getHeader(TokenUtils.getAppTokenHeader())!=null&&!"".equals(token)){
        System.out.println("方法执行前"+token);
        String userId = TokenUtils.parseToken(token);//获取用户id
        ProUser proUser = proUserMapper.selectProUserByUserId(userId);
        if (proUser == null) {
            Objects.requireNonNull(response).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            throw new ServiceException("用户信息异常，请重新登录", HttpServletResponse.SC_UNAUTHORIZED);
        }
    }

    /**
     * 对前端所有接口进行切面  来获取日志
     * @param joinPoint
     * @throws Throwable
     */
    @Before("terInfo()")
    public void terInfoBefore(JoinPoint joinPoint) throws Throwable
    {
        ServletRequestAttributes sra=(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request= Objects.requireNonNull(sra).getRequest();
        HttpServletResponse response = Objects.requireNonNull(sra).getResponse();
        String token = request.getHeader(TokenUtils.getAppTokenHeader());
        // 从请求头中获取 Token

//        if (request.getHeader(TokenUtils.getAppTokenHeader())!=null&&!"".equals(token)){
        System.out.println("方法执行前"+token);
        String userId = TokenUtils.parseToken(token);//获取用户id
        SysUser user = sysUserMapper.selectUserById(Long.valueOf(userId));
        if (user == null) {
            Objects.requireNonNull(response).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            throw new ServiceException("用户信息异常，请重新登录", HttpServletResponse.SC_UNAUTHORIZED);
        }
    }

    /**
     * 对前端所有接口进行切面  来获取日志
     * @param joinPoint
     * @throws Throwable
     */
    @Before("webLogInfo()")
    public void webLogInfo(JoinPoint joinPoint) throws Throwable
    {
        ServletRequestAttributes sra=(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request= Objects.requireNonNull(sra).getRequest();
        String token = request.getHeader(TokenUtils.getAppTokenHeader());
        System.out.println("方法执行前"+token);
        String userId = "-1";//获取用户ID
        //若登录记录用户信息
        if (request.getHeader(TokenUtils.getAppTokenHeader()) !=null&&!"".equals(token))
            userId = String.valueOf(TokenUtils.parseToken(token));
        //方法名
        String name = joinPoint.getSignature().getName();
        //类名
        String simpleName = joinPoint.getSignature().getDeclaringType().getSimpleName();
        //包名
        String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();
        int modifiers = joinPoint.getSignature().getModifiers();
        //请求方式
        String method = request.getMethod();
        Date date = new Date();
        //ip
        String ip = IpUtils.getIpAddr(request);
        //传入参数
        String content = getContent(joinPoint);
    }

    @Around("preventDuplicateSubmitPointcut()")
    public Object handleDuplicateSubmit(ProceedingJoinPoint joinPoint) throws Throwable {

        String key = generateCacheKey(joinPoint); // 生成缓存的key，这里需要根据实际情况来生成
        if ("".equals(key))
            return joinPoint.proceed(); // 继续执行原方法
        System.out.println(key);
        Object value = redisCache.getCacheObject(key);
        if (value != null) {
            new Thread(()->{
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                redisCache.deleteObject(key);
            }).start();
            throw new ServiceException("表单重复提交"); // 如果缓存中已有值，说明表单已重复提交，抛出异常
        }
        try {
            redisCache.setCacheObject(key, key, 5, TimeUnit.SECONDS); // 在方法执行前，将key放入缓存
            return joinPoint.proceed(); // 继续执行原方法
        } finally {
            redisCache.deleteObject(key); // 无论方法是否成功执行，都在finally块中删除缓存
        }
    }

    // 解析方法入参
    public String getContent(JoinPoint joinPoint) {
        Object[] paramsArray = joinPoint.getArgs();
        StringBuilder params = new StringBuilder();

        if (paramsArray != null && paramsArray.length > 0) {
            for (Object o : paramsArray) {
                if (StringUtils.isNotNull(o)) {
                    try {
                        System.out.println(o);
                        String jsonObj = JSON.toJSONString(o);
                        System.out.println(jsonObj);
                        params.append(jsonObj).append(" ");
                    } catch (Exception e) {

                    }
                }
            }
        }
        return params.toString().trim();
    }

    private String generateCacheKey(ProceedingJoinPoint joinPoint) {
        ServletRequestAttributes sra=(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request= Objects.requireNonNull(sra).getRequest();

        try {
            Long userId = SecurityUtils.getLoginUser().getUserId();
            // 从请求头中获取 Token

//        if (request.getHeader(TokenUtils.getAppTokenHeader())!=null&&!"".equals(token)){
            System.out.println("方法执行前"+userId);
            String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();
            String contentType = request.getContentType();
            String name = joinPoint.getSignature().getName();
            String content = "";
            //传入参数
            if ("application/json".equals(contentType)){
                content = getContent(joinPoint);
            }
            // 根据实际情况生成缓存的key，例如可以使用方法名、参数等信息来生成
            return userId+name+declaringTypeName+content;
        }catch (Exception e){
            return "";
        }


    }

//    /**
//     * 忽略敏感属性
//     */
//    public PropertyPreExcludeFilter excludePropertyPreFilter(String[] excludeParamNames)
//    {
//        return new PropertyPreExcludeFilter().addExcludes(ArrayUtils.addAll(PropertyPreExcludeFilter.EXCLUDE_PROPERTIES, excludeParamNames));
//    }

}